#include "task.h"
#include <algorithm>
#include <core/QbLogger.h>
#include <core/observer/message_observer.h>
#include <core/system/tick_util.h>
#include <core/sharedata/login_data.h>
#include <qbmessage/include/message_kernel.h>

#ifndef _MSC_VER
#include <arpa/inet.h>
#endif

namespace qb
{

    CTask::CTask()
        : m_eStatus(eNone)
        , m_pObserver(NULL)
    {
    }

    CTask::~CTask()
    {
        m_timer.stop();
    }

    bool CTask::IsRunning() const
    {
        return eRunning == m_eStatus;
    }

    bool CTask::IsFinished() const
    {
        return eFinished == m_eStatus;
    }

    bool CTask::IsFailed() const
    {
        return eFailed == m_eStatus;
    }

    void CTask::Start()
    {
        if (!IsRunning())
        {            
            m_eStatus = eRunning;
            StartImpl();
			StartTaskTimer();
        }
    }

    void CTask::Terminate(bool bForce /* = false */)
    {
        if (IsRunning() || bForce)
        {
            TerminateImpl();
			StopTaskTimer();
            m_eStatus = eNone;
        }
    }

    void CTask::SetObserver(ITaskObserver* pObserver)
    {
        m_pObserver = pObserver;
    }

    void CTask::NotifyFinished()
    {
        // change status
		StopTaskTimer();
        m_eStatus = eFinished;

        if (m_pObserver)
        {
            m_pObserver->OnTaskFinished(this);
        }
    }

    void CTask::NotifyFailed(qb::NetStatus status, short nRetCode)
    {
        // change status
		StopTaskTimer();
        m_eStatus = eFailed;

        if (m_pObserver)
        {
            m_pObserver->OnTaskFailed(this, status, nRetCode);
        }
    }

	void CTask::StartTaskTimer()
	{
        m_timer.start(GetTaskTimeout() * 1000, std::bind(&CTask::OnTimeout, this));
	}

	void CTask::StopTaskTimer()
	{
        m_timer.notify_stop();
	}

	void CTask::OnTimeout()
	{
		if (m_pObserver)
		{
			m_pObserver->OnTaskFailed(this, loginData::instance().GetCurrentStatus(), eNetError_TaskTimeout);
		}
	}

	void CTask::NotifyLoginStep(qb::NetStatus uStep, short nRetCode)
	{
		if (m_pObserver)
		{
			m_pObserver->OnTaskStep(uStep, nRetCode);
		}
	}

	void CTask::OnRecvNetData(char* pRecvData, int nDataLen)
	{
		if (!IsRunning())
		{
			return;
		}

		OnNetData(pRecvData, nDataLen);
	}

    void CTask::OnRecvNetStatus(int status)
    {
		if (!IsRunning())
		{
			return;
		}

		OnNetStatus(status);
    }
}
